#include "TSocket.h"
#ifdef WIN32
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#endif

#ifdef WIN32
#define close			closesocket
#define socklen_t		int
#else
#define INVALID_SOCKET	-1
#endif
bool TSocket::EnvInit()
{
#ifdef WIN32
    WSADATA wsaData;
    if (0 != WSAStartup(MAKEWORD(2,2), &wsaData))
    {
        WSACleanup();
        return false;
    }
#endif
    return true;
}

void TSocket::EnvFree()
{
#ifdef WIN32
    WSACleanup();
#endif
}

TSocket::TSocket()
{
    sockfd_ = -1;
}

TSocket::TSocket(int sockfd)
{
    sockfd_ = sockfd;
}

TSocket::~TSocket()
{
    //Close();
}

bool TSocket::Validate()
{
    return -1 != sockfd_;
}

bool TSocket::Listen(char* host, int port)
{
    sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(port);
    if (-1 == bind(sockfd_, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)))
    {
        return false;
    }
    if (-1 == listen(sockfd_, 1024))
    {
        return false;
    }
    return true;
}

TSocket* TSocket::Accept()
{
    int sin_size = sizeof(struct sockaddr_in);
    struct sockaddr_in client_addr;
    return new TSocket(accept(sockfd_, (struct sockaddr*)&client_addr, (socklen_t*)&sin_size));
}

bool TSocket::Connect(char* host, int port)
{
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(host);
    server_addr.sin_port = htons(port);
    if (-1 == connect(sockfd_, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)))
    {
        return false;
    }
    return true;
}

int TSocket::Send(char* buff, int len)
{
    int nwritten = send(sockfd_, buff, len, 0);
    return nwritten;
}

int TSocket::Recv(char* buff, int len)
{
    int nread = recv(sockfd_, buff, len, 0);
    if (nread == 0) return nread;
    if (nread == -1)
    {
#ifdef WIN32
        int error = GetLastError();
        if (WSAEWOULDBLOCK == error) return nread;
#else
        if (EAGAIN == errno) return nread;
#endif
        return -1;
    }
    return nread;
}

void TSocket::Close()
{
    close(sockfd_);
    sockfd_ = INVALID_SOCKET;
}

bool TSocket::SetNonBlock(bool block)
{
    int on = 1;
#ifdef WIN32
    setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
    unsigned long ul = block ? 0 : 1;
    return SOCKET_ERROR != ioctlsocket(sockfd_, FIONBIO, (unsigned long*)&ul);
#else
    setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    int flags = fcntl(sockfd_, F_GETFL, 0);
    if (block) return (-1 == fcntl(sockfd_, F_SETFL, flags|O_NONBLOCK));
    else return (-1 == fcntl(sockfd_, F_SETFL, flags&(~O_NONBLOCK&0xffffffff)));
#endif
}


